use std::collections::HashMap;

use crate::types::{share, SequenceNumber, Shared, MAX_SEQUENCE_NUMBER};

use std::rc::Rc;

/// Opaque snapshot handle; Represents index to SnapshotList.map
///
/// 这段这段代码定义了一个名为 SnapshotHandle 的类型别名，本质是将 u64（64 位无符号整数）重新命名为 SnapshotHandle，
/// 用于表示数据库中快照的不透明句柄（Opaque Handle）。
type SnapshotHandle = u64;

/// An InnerSnapshot is shared by several Snapshots. This enables cloning snapshots, and a snapshot
/// is released once the last instance is dropped.
///
/// 这个 InnerSnapshot 结构体是数据库快照（Snapshot）的核心内部表示，用于在多个快照实例之间共享状态，并管理快照的生命周期（创建、克隆、释放）。
/// 它是连接用户层快照操作与底层快照列表管理的关键结构。
///
/// 典型使用流程:
///
/// 创建快照：用户调用 db.new_snapshot()，数据库生成一个新的 SnapshotHandle 和对应的 SequenceNumber，创建 InnerSnapshot 实例并加入 InnerSnapshotList，返回给用户一个包含该实例的对象；
///
/// 克隆快照：用户对快照调用 clone()，生成新的 InnerSnapshot 实例（共享 id、seq 和 sl），引用计数增加；
///
/// 使用快照查询：查询时传入快照，数据库通过 InnerSnapshot.seq 确保只返回该序列号之前的数据；
///
/// 释放快照：当所有克隆实例都被销毁（drop），引用计数归 0，InnerSnapshot 通过 sl 通知 InnerSnapshotList 移除该快照，完成清理。
///
///
/// InnerSnapshot 是快照的核心数据载体，通过以下特性支撑数据库的快照功能：
///
/// 轻量克隆：允许高效复制快照，共享同一数据视图；
///
/// 生命周期管理：基于引用计数自动清理不再使用的快照；
///
/// 连接上下层：关联用户操作与底层快照列表的管理逻辑。
#[derive(Clone)]
struct InnerSnapshot {
    /// 快照的唯一标识符（即之前定义的 u64 类型别名），用于关联到底层 InnerSnapshotList.map 中的条目；
    /// 作用：通过该 ID 可以在快照列表中定位到对应的元数据。
    id: SnapshotHandle,
    /// 快照对应的序列号，记录了创建快照时数据库的最新操作版本；
    /// 作用：查询数据时，数据库会基于该序列号过滤操作（只返回该序列号之前的版本），确保快照视图的一致性。
    seq: SequenceNumber,
    /// 指向全局快照列表（InnerSnapshotList）的共享指针（线程安全的引用）；
    /// 作用：当快照被释放（最后一个实例被销毁）时，通过该指针通知 InnerSnapshotList 移除对应的快照条目。
    sl: Shared<InnerSnapshotList>,
}

impl Drop for InnerSnapshot {
    fn drop(&mut self) {
        self.sl.borrow_mut().delete(self.id);
    }
}

/// 这个 Snapshot 结构体是数据库对外暴露的快照公共接口类型，用于向用户提供安全、便捷的快照操作能力。它通过 Rc 智能指针包裹内部的 InnerSnapshot，实现了快照的轻量克隆和自动生命周期管理。
#[derive(Clone)]
pub struct Snapshot {
    /// Rc（Reference Counted，引用计数）是 Rust 中的智能指针，用于在单线程环境下实现数据的共享访问，并跟踪引用数量；
    /// 它指向 InnerSnapshot 实例（即包含快照 ID、序列号和快照列表引用的内部结构）。
    inner: Rc<InnerSnapshot>,
}

impl Snapshot {
    pub fn sequence(&self) -> SequenceNumber {
        self.inner.seq
    }
}

/// A list of all snapshots is kept in the DB.
///
/// 这个 InnerSnapshotList 结构体是数据库中管理快照（Snapshot）的核心数据结构，用于维护所有活跃的快照实例，并跟踪它们的创建顺序（最新和最旧的快照）。
/// 快照是数据库提供的一种一致性读机制，允许用户在某个时间点 “冻结” 数据库状态，后续即使数据被修改，也能通过快照查看当时的一致性视图。
struct InnerSnapshotList {
    /// 存储所有活跃快照的映射表：
    /// 键（SnapshotHandle）：快照的句柄（标识一个具体的快照实例，供用户持有和操作）；
    /// 值（SequenceNumber）：快照对应的序列号（数据库在该序列号时的状态被 “冻结”）。
    /// 作用：通过句柄快速查找快照对应的序列号，确定该快照能看到的最大操作版本。
    map: HashMap<SnapshotHandle, SequenceNumber>,
    /// 指向当前最新创建的快照句柄。
    /// 作用：快速获取最新的快照，便于新快照创建时更新链表关系（通常快照按创建顺序形成链表）。
    newest: SnapshotHandle,
    /// 指向当前最旧的活跃快照句柄。
    /// 作用：快速定位最早创建的快照，便于在快照过期时（如用户释放）清理资源，或判断数据是否可以安全删除（旧于最旧快照的数据可能仍需保留）。
    oldest: SnapshotHandle,
}

/// 这个 SnapshotList 结构体是 InnerSnapshotList 的线程安全封装，用于在多线程环境下安全地管理数据库快照（Snapshot）。
/// 它通过 Shared 智能指针（通常是 Arc 或自定义的线程安全共享指针）包装核心的快照管理逻辑，确保多个线程可以并发访问和修改快照列表，同时保证数据一致性。
pub struct SnapshotList {
    /// Shared 是 Rust 中用于实现线程安全共享访问的智能指针（常见于 rusty_leveldb 等库的实现，本质类似 std::sync::Arc，可能额外结合了锁或原子操作）；
    /// 它指向 InnerSnapshotList 实例（即之前分析的、负责维护快照映射表和顺序的核心数据结构）。
    inner: Shared<InnerSnapshotList>,
}

impl SnapshotList {
    pub fn new() -> SnapshotList {
        SnapshotList {
            inner: share(InnerSnapshotList {
                map: HashMap::new(),
                newest: 0,
                oldest: 0,
            }),
        }
    }

    /// 这个 new_snapshot 方法是创建数据库新快照的核心函数，用于在指定序列号（SequenceNumber）处生成一个新的快照（Snapshot），并将其添加到快照列表中管理。
    /// 快照可以让用户查看数据库在该序列号对应的时间点的一致性状态，即使后续数据被修改也不受影响。
    ///
    /// new_snapshot 方法的核心价值是在指定时间点（序列号）创建快照并纳入管理，具体作用包括：
    ///
    /// 生成唯一快照标识：通过 sl.newest 自增确保每个快照有唯一句柄，避免冲突；
    ///
    /// 记录快照元数据：将句柄与序列号关联并存入 sl.map，为后续查询和释放提供依据；
    ///
    /// 维护快照顺序：更新 sl.newest 和 sl.oldest 跟踪快照的创建顺序，便于后续清理旧快照；
    ///
    /// 返回用户可用的快照对象：封装 InnerSnapshot 为 Snapshot 类型，提供安全的用户层接口。
    pub fn new_snapshot(&mut self, seq: SequenceNumber) -> Snapshot {
        // self.inner 是指向 InnerSnapshotList（快照列表核心数据结构）的共享指针（如 Rc<RefCell<InnerSnapshotList>>）；
        // inner.clone() 复制共享指针，用于后续关联到新快照；
        // self.inner.borrow_mut() 获取可变引用，用于修改快照列表（添加新快照）。
        let inner = self.inner.clone();
        let mut sl = self.inner.borrow_mut();
        // 快照句柄（SnapshotHandle）通过 sl.newest 自增生成，保证每个快照有唯一标识；
        // 将新句柄（newest）和对应的序列号（seq）存入 sl.map（快照句柄到序列号的映射），完成快照元数据的记录。
        sl.newest += 1; // 最新快照句柄自增（确保唯一性）
        let newest = sl.newest;
        sl.map.insert(newest, seq); // 将新快照句柄与序列号关联，存入映射表

        if sl.oldest == 0 {
            sl.oldest = sl.newest; // 若为第一个快照，最旧句柄等于最新句柄
        }
        // 封装 InnerSnapshot 实例（包含快照的核心信息），并通过 Rc 智能指针管理其生命周期；
        // 返回 Snapshot 对象给用户，用户可通过该对象查询对应时间点的数据库状态。
        Snapshot {
            inner: Rc::new(InnerSnapshot {
                id: sl.newest, // 新快照的句柄（唯一标识）
                seq, // 快照对应的序列号（时间点）
                sl: inner,  // 指向快照列表的共享指针（用于后续释放）
            }),
        }
    }

    /// oldest returns the lowest sequence number of all snapshots. It returns 0 if no snapshots
    /// are present.
    ///
    /// 这个 oldest 方法用于获取所有快照中最小的序列号（即最早创建的快照对应的数据库版本），是数据库快照管理中的一个辅助查询接口。
    /// 它能帮助系统判断哪些历史数据可以安全清理，或确定数据可见性的下限。
    ///
    /// oldest 方法的核心价值是确定所有快照的时间下限，主要应用场景包括：
    ///
    /// 数据清理决策:
    ///
    /// 在 LSM 树的压缩（compaction）过程中，系统需要判断哪些历史数据可以安全删除。由于快照可能引用旧版本数据，任何序列号大于等于 “最旧快照序列号” 的数据都不能删除（否则快照查询会出错）。oldest 方法提供了这个安全下限。
    ///
    /// 可见性判断:
    ///
    /// 当处理查询时，若操作需要考虑快照的可见性（如 “只能看到某个时间点之前的数据”），oldest 可以作为所有快照可见范围的起点，辅助验证数据版本的合法性。
    ///
    /// 快照管理优化:
    ///
    /// 系统可以通过 oldest 监控最旧快照的时间，若存在长期未释放的旧快照（导致大量历史数据无法清理），可发出警告或自动清理策略。
    pub fn oldest(&self) -> SequenceNumber {
        // fold 函数的作用是遍历 map 中所有快照的序列号（seq），通过比较找到最小值；
        // 初始值设为 MAX_SEQUENCE_NUMBER（最大序列号），确保任何实际序列号都会比它小，从而正确更新最小值。
        let oldest = self
            .inner
            .borrow() // 获取快照列表的共享访问
            .map // 访问存储快照句柄与序列号的映射表（key: 句柄，value: 序列号）
            .iter()  // 迭代所有快照条目
            .fold( // 折叠计算，找到最小的序列号
                MAX_SEQUENCE_NUMBER, // 初始值设为最大可能的序列号
                |s, (seq, _)| if *seq < s { *seq } else { s }, // 比较并保留较小的序列号
            );
        if oldest == MAX_SEQUENCE_NUMBER {
            0  // 若没有快照（map 为空），返回 0
        } else {
            oldest  // 否则返回找到的最小序列号
        }
    }

    /// newest returns the newest sequence number of all snapshots. If no snapshots are present, it
    /// returns 0.
    ///
    /// 这个 newest 方法用于获取所有快照中最大的序列号（即最新创建的快照对应的数据库版本），是数据库快照管理中的一个辅助查询接口。
    /// 它能帮助系统了解当前快照覆盖的最新数据版本，辅助判断数据可见性或快照有效性。
    ///
    /// newest 方法的核心价值是确定所有快照的时间上限，主要应用场景包括：
    ///
    /// 数据可见性验证:
    ///
    /// 当处理基于快照的查询时，若某个操作的序列号大于 newest() 返回的值，说明该操作发生在所有快照创建之后，不会被任何快照包含，可快速判断其对快照查询的不可见性。
    ///
    /// 快照有效性检查:
    ///
    /// 若系统最新的全局序列号远大于 newest()，说明当前所有快照都已过时（未包含最新数据），可提示用户创建新快照以获取最新视图。
    ///
    /// 并发操作协调:
    ///
    /// 在多线程环境中，可通过 newest() 了解当前快照覆盖的最新版本，辅助协调读写操作（如避免删除仍被最新快照引用的数据）。
    pub fn newest(&self) -> SequenceNumber {
        // fold 函数的作用是遍历 map 中所有快照的序列号（seq），通过比较找到最大值；
        // 初始值设为 0，若没有快照（map 为空），则直接返回 0；若有快照，则会更新为最大的序列号。
        self.inner
            .borrow() // 获取快照列表的共享访问
            .map // 访问存储快照句柄与序列号的映射表（key: 句柄，value: 序列号）
            .iter()  // 迭代所有快照条目
            .fold(0, |s, (seq, _)| if *seq > s { *seq } else { s }) // 初始值设为 0（无快照时的默认返回值）, 比较并保留较大的序列号
    }

    /// 这个 empty 方法用于判断当前是否存在活跃的快照，是快照列表的状态检查工具。它通过检查最旧快照的句柄状态，快速判断快照列表是否为空。
    pub fn empty(&self) -> bool {
        // self.inner.borrow() 获取快照列表（InnerSnapshotList）的共享访问；
        // 检查 oldest 字段是否为 0：
        // 在快照列表中，oldest 用于记录最旧的活跃快照句柄（SnapshotHandle）；
        // 当没有任何活跃快照时，oldest 会被初始化为 0（如首次创建快照前的状态）；
        // 一旦创建了第一个快照，oldest 会被更新为该快照的句柄（非 0 值），且后续即使有新快照加入或旧快照释放，只要仍有活跃快照，oldest 也不会再回到 0。
        self.inner.borrow().oldest == 0
    }
}

impl InnerSnapshotList {
    fn delete(&mut self, id: SnapshotHandle) {
        self.map.remove(&id);
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[allow(unused_variables)]
    #[test]
    fn test_snapshot_list() {
        let mut l = SnapshotList::new();

        {
            assert!(l.empty());
            let a = l.new_snapshot(1);

            {
                let b = l.new_snapshot(2);

                {
                    let c = l.new_snapshot(3);

                    assert!(!l.empty());
                    assert_eq!(l.oldest(), 1);
                    assert_eq!(l.newest(), 3);
                }

                assert_eq!(l.newest(), 2);
                assert_eq!(l.oldest(), 1);
            }

            assert_eq!(l.oldest(), 1);
        }
        assert_eq!(l.oldest(), 0);
    }
}
